#include "Scene.h"
#include <unistd.h>
#include <iostream>
#include <fstream>
#include <set>
using namespace std;

/* 带参构造 */
Scene::Scene(Player &p) : p(p)
{
    for (int i = 0; i < MapSize; i++)
    {
        for (int j = 0; j < MapSize; j++)
        {
            Map[i][j] = "📖";
        }
    }
    // InitMonsters();     //初始化怪兽
    // InitTreasureBox();  //初始化宝箱
}
Scene::Scene(Player &p, std::vector<Monster> &monsters) : p(p), monsters(monsters)
{
    for (int i = 0; i < MapSize; i++)
    {
        for (int j = 0; j < MapSize; j++)
        {
            Map[i][j] = "📖";
        }
    }
}
/* 清屏 */
void Scene::Clear()
{
    for (int i = 0; i < MapSize; i++)
    {
        for (int j = 0; j < MapSize; j++)
        {
            Map[i][j] = "📖";
        }
    }
}

/* 设定怪兽 */
void Scene::InitMonsters()
{
    bool occupied[MapSize][MapSize] = {false}; // 标记地图上的位置是否已被占据

    // 定义一个生成唯一坐标的函数
    // 匿名函数 []捕捉列表，引用捕捉，捕捉变量本身可以修改值
    auto UniquePosition = [&](int &x, int &y)
    {
        while (true) // 位置被占据
        {
            x = rand() % MapSize;
            y = rand() % MapSize;
            if (!occupied[y][x]) // 如果位置未被占据
            {
                occupied[y][x] = true; // 标记该位置为已占据
                break;
            }
        }
    };

    // 初始化不同类型的怪兽，保持参数数量不变
    int x, y;

    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "哥布林", "👾", 10, 2, 2, 20, 40));
    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "哥布林", "👾", 10, 2, 2, 20, 40));
    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "哥布林", "👾", 10, 2, 2, 20, 40));
    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "哥布林", "👾", 10, 2, 2, 20, 40));
    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "哥布林", "👾", 10, 2, 2, 20, 40));

    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "骨头骑士", "💀", 20, 5, 3, 50, 80));
    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "骨头骑士", "💀", 20, 5, 3, 50, 80));
    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "骨头骑士", "💀", 20, 5, 3, 50, 80));

    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "巨龙", "🐉", 40, 10, 5, 100, 100));
    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "巨龙", "🐉", 40, 10, 5, 100, 100));

    UniquePosition(x, y);
    monsters.push_back(Monster(x, y, "魔王", "🐙", 100, 20, 10, 200, 1000));
}

/* 打印场景 */
void Scene::show()
{
    Clear();
    cout << endl;
    cout << "==================欢迎来到魔塔世界🎮=================\n";
    Map[p.GetY()][p.GetX()] = p.GetSymbol();                        // 打印玩家标志
    for (auto ite = monsters.begin(); ite != monsters.end(); ite++) // 遍历打印怪兽标志
    {
        if (ite->GetHP() > 0) // 血条大于0才打印
            Map[ite->GetY()][ite->GetX()] = ite->GetSymbol();
        //std::cout << "场景的Monster: " << ite->GetX() << " " << ite->GetY() << std::endl;
        // sleep(1);
    }

    for (auto ite = treasureBoxes.begin(); ite != treasureBoxes.end(); ite++) // 遍历打印怪兽标志
    {
        Map[ite->GetY()][ite->GetX()] = ite->GetSymbol();
    }

    for (int i = 0; i < MapSize; i++)
    {
        cout << "            ";
        for (int j = 0; j < MapSize; j++)
        {
            printf("%5s", Map[i][j].c_str()); // 返回指向空终止内容的常量指针
        }
        std::cout << std::endl;
    }
}

/* 判断是否满足战斗条件，满足则返回该怪兽地址 */
Monster *Scene::IsPosEqual()
{ // 遍历查看是哪一个怪兽要战斗
    for (auto ite = monsters.begin(); ite != monsters.end(); ite++)
    { // 怪兽血条大于0；且怪兽位置和玩家位置相同
        if (ite->GetHP() > 0 && ite->GetX() == p.GetX() && ite->GetY() == p.GetY())
        {
            return &(*ite); // 返回迭代器
        }
    }
    return nullptr; // 加*来判断非法值
}

/* 战斗规则函数 */
void Scene::Fight(Monster *m)
{
    while (1) // 死循环，为啥
    {
        system("clear"); // 清屏
        p.show();        // 打印玩家和怪兽信息
        m->show();
        std::cout << endl;
        // std::cout<<"==========================战斗========================\n";
        std::cout << "|| 请选择你的攻击模式：" << std::endl;
        std::cout << "|| 1、普通攻击 " << std::endl;
        std::cout << "|| 2、暴击 " << std::endl;
        std::cout << "|| 3、逃跑 " << std::endl;

        int c = 0;
        std::cin >> c;
        switch (c)
        {
        case 1:
        {
            Player2Monster(m); // 玩家普攻怪兽
            Monster2Player(m); // 怪兽普攻玩家
            break;
        }
        case 2:
        {
            Player2Monster(m, 2, 2); // 玩家暴击怪兽
            Monster2Player(m);       // 怪兽普攻玩家
            break;
        }
        case 3:
        {
            if (Escape(3)) // 玩家逃跑，参数是逃跑成功的概率
            {
                sleep(1); // 如果逃跑成功，程序休眠1秒，增加交互体验
                return;
            }
            Monster2Player(m); // 反之，没逃跑成功，怪兽普攻玩家
            break;
        }
        default:
            break;
        }
        sleep(1);
        /* =================判断战斗后结果================= */
        // 玩家血条小于0，玩家失败
        if (p.GetHP() <= 0)
        {
            printf("你失败了！游戏结束！\n");
            exit(0); // 退出程序
        }
        // 怪兽血条小于0， 玩家获胜
        if (m->GetHP() <= 0)
        {
            printf("你战胜了|%s|!\n", m->GetName().c_str());
            p.SetExp(m->GetExp() + p.GetExp()); // 玩家获取怪兽的经验值
            sleep(1);
            p.SetMoney(m->GetMoney() + p.GetMoney());
            sleep(1);
            p.LevelUp(); // 判断玩家等级是否提升
            sleep(1);
            if (m->GetName() != "魔王")
            {
                RefreshMonster(m); // 杀掉一个怪兽，刷新一个同等级的怪兽
            }
            else
            {
                cout << "🏆 恭喜你通关完成！！！\n欢迎再次来到魔塔世界！\n";
                exit(-1);
            }
            return;
        }
        sleep(1);
    }
}

/* 玩家普攻怪兽 */
void Scene::Player2Monster(Monster *m)
{
    int damage = p.GetAttack() - m->GetDefends(); // 伤害值 = 玩家攻击力 - 怪兽防御力
    if (damage <= 0)                              // 伤害小于0
    {
        printf("我们未能击穿敌方装甲！\n");
    }
    else // 伤害小于0
    {
        std::cout << "|" << p.GetName() << "|对|" << m->GetName() << "|发起普通攻击,造成|" << damage << "|点伤害" << std::endl;
        m->SetHP(m->GetHP() - damage); // 怪兽被攻击后剩余的血条
    }
}

/* 玩家暴击怪兽：随机事件 */
void Scene::Player2Monster(Monster *m, int Rate, int mutiple)
{
    // 程序修眠，sleep
    srand(time(nullptr));
    int rate = rand() % Rate; // 随机值，rate分之一的概率
    if (rate == 0)
    {
        printf("|%s|暴击失败！\n", p.GetName().c_str());
    }
    else
    {                                                           /*暴击成功。计算伤害量*/
        int damage = mutiple * p.GetAttack() - m->GetDefends(); // 伤害值 = 玩家攻击力 - 怪兽防御力
        printf("|%s|暴击成功！对|%s|造成双倍伤害\n", p.GetName().c_str(), m->GetName().c_str());
        if (damage <= 0)
        {
            printf("我们未能击穿敌方装甲！\n");
        }
        else
        {
            printf("伤害值为|%d!|\n", damage);
            m->SetHP(m->GetHP() - damage); // 怪兽剩余血条
        }
    }
}

/* 怪兽普攻玩家 */
void Scene::Monster2Player(Monster *m)
{
    int damage = m->GetAttack() - p.GetDefends(); // 伤害值 = 怪兽攻击力 - 玩家防御力
    if (damage <= 0)
    {
        printf("敌方攻击就像挠痒痒！\n");
    }
    else
    {
        std::cout << "|" << m->GetName() << "|对|" << p.GetName() << "|发起普通攻击" << std::endl;
        p.SetHP(p.GetHP() - damage); // 玩家剩余血条
    }
}

/* 玩家逃跑：随机事件 */
bool Scene::Escape(int Rate)
{
    srand(time(nullptr));
    int rate = rand() % Rate;
    if (rate == 0)
    {
        printf("|%s|逃跑成功！\n", p.GetName().c_str());
        return true; // 跑掉了
    }
    else
    {
        printf("|%s|逃跑失败！\n", p.GetName().c_str());
        return false;
    }
}

/* 刷新怪兽 */
void Scene::RefreshMonster(Monster *m)
{
    m->SetHP(m->GetMaxHP()); // 怪兽血条复原
    /* 随机刷新位置 */
    bool occupied[MapSize][MapSize] = {false}; // 标记地图上的位置是否已被占据

    // 定义一个生成唯一坐标的函数
    // 匿名函数 []捕捉列表，引用捕捉，捕捉变量本身可以修改值
    auto UniquePosition = [&](int &x, int &y)
    {
        while (true) // 位置被占据
        {
            x = rand() % MapSize;
            y = rand() % MapSize;
            if (!occupied[y][x]) // 如果位置未被占据
            {
                occupied[y][x] = true; // 标记该位置为已占据
                break;
            }
        }
    };

    // 初始化不同类型的怪兽，保持参数数量不变
    int x, y;

    UniquePosition(x, y);
    m->SetX(x);
    m->SetY(y);
}

const std::vector<Monster> &Scene::GetMonsters()
{
    return monsters;
}

// void Scene::SetMonsters(const std::vector<Monster> monsters)
// {
//     this->monsters = monsters;
// }

const std::vector<TreasureBox> &Scene::GetTreasureBoxes()
{
    return treasureBoxes;
}

// void Scene::SetTreasureBoxes(const std::vector<TreasureBox> treasureBoxes)
// {
//     this->treasureBoxes = treasureBoxes;
// }

void Scene::InitTreasureBox()
{
    bool occupied[MapSize][MapSize] = {false}; // 标记地图上的位置是否已被占据

    auto UniquePosition = [&](int &x, int &y)
    {
        while (true)
        {
            x = rand() % MapSize;
            y = rand() % MapSize;
            if (!occupied[y][x] && !IsOverlappingWithMonster(x, y))
            { // 确保位置不与怪兽重合
                occupied[y][x] = true;
                break;
            }
        }
    };

    int x, y;

    UniquePosition(x, y);
    treasureBoxes.push_back(TreasureBox(x, y, "金钱", "🎁", 2, 0, 0, 0));
    UniquePosition(x, y);
    treasureBoxes.push_back(TreasureBox(x, y, "血条", "🎁", 0, 2, 0, 0));
    UniquePosition(x, y);
    treasureBoxes.push_back(TreasureBox(x, y, "攻击", "🎁", 0, 0, 2, 0));
    UniquePosition(x, y);
    treasureBoxes.push_back(TreasureBox(x, y, "防御", "🎁", 0, 0, 0, 2));
}

bool Scene::IsOverlappingWithMonster(int x, int y)
{
    for (auto ite = monsters.begin(); ite != monsters.end(); ite++)
    {
        if (x == ite->GetX() && y == ite->GetY())
        {
            return true;
        }
    }
    return false;
}

/* 判断是否碰到宝箱，如果是，返回该宝箱地址 */
TreasureBox *Scene::TIsPosEqual()
{
    for (auto ite = treasureBoxes.begin(); ite != treasureBoxes.end(); ite++)
    {
        if (ite->GetX() == p.GetX() && ite->GetY() == p.GetY())
        {
            return &(*ite); // 返回迭代器
        }
    }
    return nullptr; // 加*来判断非法值
}

void Scene::OpenBox(TreasureBox *t)
{
    cout << "🎉你遇见了一个宝箱，猜猜是什么?\n";
    cin.get();
    sleep(1);
    if (t->GetMoney() != 0)
    {
        p.SetMoney(p.GetMoney() + t->GetMoney());
        cout << "你获得了" << t->GetMoney() << " 金币！" << endl;
    }
    else if (t->GetHP() != 0)
    {
        p.SetHP(p.GetHP() + t->GetHP());
        cout << "你获得了" << t->GetHP() << " 血量！" << endl;
    }
    else if (t->GetAttack() != 0)
    {
        p.SetAttack(p.GetAttack() + t->GetAttack());
        cout << "你获得了" << t->GetAttack() << " 攻击力！" << endl;
    }
    else if (t->GetDefends() != 0)
    {
        p.SetDefends(p.GetDefends() + t->GetDefends());
        cout << "你获得了" << t->GetDefends() << " 防御力！" << endl;
    }
    for (auto it = treasureBoxes.begin(); it != treasureBoxes.end(); ++it)
    {
        if (&(*it) == t)
        {
            treasureBoxes.erase(it);
            break;
        }
    }
    // p.show();
    cout << "按Enter键继续游戏";
    cin.get();
}
